#! -*-coding: utf-8 -*-
from loadDll import LoadDll
from allEnum import *
from log import AsLogger
from zipfile import ZipFile, ZIP_DEFLATED
import time, os, sys, re, math
from configRead import ConfigFileRead
from serialLinster import serialLinster
from assertLinster import assertLinster
from DiagReadLinster import DiagReadLinster
import serial.tools.list_ports as serailPort
from AutoSanityBsSim.diagDataAsBsim import *
from AutoSanityBsSim.Const import *
import shutil

diagCom = DiagCommand()
logObj = AsLogger()

def assertWait(func):
    def __waitAssertCatcher(cls, *args, **kwargs):
        i = 0
        while i < 400:
            if cls.checkCatcherAssertLog():
                time.sleep(10)
            else:
                break
            time.sleep(2)
            i += 1

        result = func(cls, *args, **kwargs)
        try:
            if isinstance(result, (list,set,tuple)):

                if result.index(0) == False:

                    flg, res = cls.SP_SendATCommand("AT", True, 5000)

                    if flg == False:
                        if cls.checkDiagOnline() == False:
                            print "reset diag port"
                            cls.initDiagPort()
                        else:
                            print "reset diag port1"
                            cls.endPhoneTest()
                            time.sleep(1)
                            cls.beginPhoneTest()

        except Exception as e:
            pass
        return result
    return __waitAssertCatcher


class PhoneCommand(LoadDll):
    def __init__(self, port=0, baudrate=115200):
        LoadDll.__init__(self)
        self.port = int(str(port)[3:]) if "com" in str(port).lower() else int(port)
        self.baudrate = baudrate

        if self.port == 0:
            raise Exception("COM{} is error!".format(port))

        self.zipfile = True
        self.testcasepath = os.path.split(os.path.abspath(sys.argv[0]))[0]

        self.__deleteLogFile()
        # self._monitorDiag()
        self.assertlinster = None
        self.linster = None

        self.loaddll()
        self.createISplog()
        self.SP_CreatePhone()
        self.vid = self.initVidByPort()
    def __del__(self):
        if self.zipfile:
            self.endPhoneTest()

        self.SP_ReleasePhone()
        self._zipFile()
        self.zipfile = False

    def __deleteLogFile(self):
        file_list = os.listdir(self.testcasepath)
        for name in file_list:
            if name in ["Arm.Logel", "Assert.ass", "Assert.Logel"]:
                os.remove(os.path.join(self.testcasepath, name))
            if name in ["assertApLog","assertMsLog"]:
                try:
                    shutil.rmtree(os.path.join(self.testcasepath,name),ignore_errors=True)
                except Exception as e :
                    pass

    def checkCatcherAssertLog(self):
        """
            检查当前手机是否抓取assertlog
            :return: True/False
            """
        if self.assertlinster is not None:
            return self.assertlinster.getAssertFlag()
        return False

    def checkInAssertApStatus(self):
        """
        检查当前手机是否处于assert ap 状态
        :return: True/False
        """
        if self.linster is not None:
            return self.linster.getAssertApFlag()
        return False

    def _monitorAssert(self):
        self.assertlinster = assertLinster(self, self.port, self.baudrate)
        self.assertlinster.setDaemon(True)
        self.assertlinster.start()

    def __monitorDiagRead(self):

        self.DaigReadlinster = DiagReadLinster(self)
        self.DaigReadlinster.setDaemon(True)
        self.DaigReadlinster.start()

    def _monitorDiag(self):
        self.linster = serialLinster(self.port, self.baudrate, self)
        self.linster.setDaemon(True)
        self.linster.start()


    def _string_ip_to_int(self, ipStr):
        reg = "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
        matchObj = re.match(reg, ipStr)
        ipInt = 0
        if matchObj:
            ipList = ipStr.split(".")
            for key, value in enumerate(ipList):
                ipInt += int(value) * math.pow(256, 3 - key)
        return int(ipInt)

    def _zipFile(self):
        aslog = AsLogger()
        logPath = aslog.getLogFileName()
        zipName = os.path.split(logPath)[1].replace(".log",".zip")
        zipobj = ZipFile(os.path.join(os.path.split(logPath)[0], zipName),
                      "w",
                      ZIP_DEFLATED)
        zipobj.write(logPath,os.path.split(logPath)[1])

        self._zipArmlog(zipobj)
        self._zipAssertApLog(zipobj)
        zipobj.close()

    def _zipArmlog(self, zipObj):
        file_list = os.listdir(self.testcasepath)
        for name in file_list:
            fp = os.path.join(self.testcasepath, name)
            if name.endswith(".py"):
                continue
            elif os.path.isdir(fp):
                continue
            elif name.endswith(".Logel") or name.endswith(".log") or name.endswith(".ass"):
                zipObj.write(fp, name)
            else:
                continue

    def _zipAssertApLog(self, zipObj):

        if not os.path.exists(os.path.join(self.testcasepath,"assertApLog")):
            return

        for path, dirList, fileList in os.walk(os.path.join(self.testcasepath,"assertApLog")):
            dirName = path[len(self.testcasepath)+1: ]
            for name in fileList:
                fp = os.path.join(path, name)
                zipObj.write(fp,os.path.join(dirName, name))
        if not os.path.exists(os.path.join(self.testcasepath, "assertMsLog")):
            return

        for path, dirList, fileList in os.walk(os.path.join(self.testcasepath, "assertMsLog")):
            dirName = path[len(self.testcasepath) + 1:]
            for name in fileList:
                fp = os.path.join(path, name)
                zipObj.write(fp, os.path.join(dirName, name))
    def beginPhoneTest(self):
        """
        启动端口，为测试开启进程
        :return:True/False
        """
        # self.loaddll()
        # self.createISplog()
        # self.SP_CreatePhone()
        if not self.checkDiagOnline():
            time.sleep(20)
            if not self.checkDiagOnline():
                print ("Diag Port(COM{}) is except, please check!".format(self.port))

        return self.SP_BeginPhoneTest(self.port, self.baudrate)

    def endPhoneTest(self):
        """
        关闭端口，释放资源
        :return:
        """
        self.SP_EndPhoneTest()
        # self.SP_ReleasePhone()
        # self._zipFile()
        # self.zipfile = False

    def checkDiagOnline(self):
        """
        在初始化端口时候，检查端口时间是否存在，检查时间为20秒
        :return:
        """
        comPort = "COM"+str(self.port)
        for portInfo in list(serailPort.comports()):
            if comPort == portInfo.device:
                return True

        if self.vid == 0:
            return False

        allComInfo = serailPort.comports()
        for portInfo in allComInfo:
            if portInfo.description.lower().find(u"sprd diag") != -1 and self.vid == portInfo.vid:
                self.port = int(str(portInfo.device)[3:])

        return False

    def initVidByPort(self):
        com_port = "COM" + str(self.port)
        allComInfo = serailPort.comports()

        for portInfo in allComInfo:
            if portInfo.device.lower() == com_port.lower() and portInfo.vid != 0:
                print "vid =",portInfo.vid
                return portInfo.vid

        return 0

    def initDiagPort(self):
        if self.vid == 0:
            return

        allComInfo = serailPort.comports()

        try:
            for portInfo in allComInfo:
                if portInfo.description.lower().find(u"sprd diag") != -1 and self.vid == portInfo.vid:
                    port = int(str(portInfo.device)[3:])
                    self.SP_EndPhoneTest()
                    time.sleep(1)
                    self.SP_BeginPhoneTest(port, self.baudrate)
        except Exception as e:
            print e

    @assertWait
    def sendRestartPhone(self):
        """
        重启DUT
        :return:函数执行成功，True。执行失败：False
        """
        # self.log.error("send error")
        return self.SP_RestartPhone()

    @assertWait
    def sendDeepSleep(self):
        """
        控制DUT进入Deep Sleep模式
        手机一旦进入DeepSleep模式之后，无法进行任何DIAG命令通信，
        除非重启DUT重新握手进入测试模式。通常情况下在DeepSleep模式下测量漏电电流。
        :return:函数执行成功，True。执行失败：False
        """
        return self.SP_DeepSleep()

    @assertWait
    def sendPowerOff(self):
        """
        关机
        :return:函数执行成功，True。执行失败：False
        """
        self.SP_PowerOff()

    @assertWait
    def sendGetSWVer(self, swverType):
        """
        获取CP、AP的版本号
        :param swverType:指定读取的版本类型，CP 或AP
        :return:(True/False,result)
        """
        if swverType is None or swverType not in SwverType.__dict__.values():
            raise Exception("[sendGetSWVer]: swverType must be cp or ap!")

        return self.SP_GetSWVer(swverType)

    @assertWait
    def sendLoadSN(self, snType):
        """
        从手机中读取序列号SN
        :param snType:SN1/SN2
        :return:(True/False,result)
        """
        if snType is None or snType not in SnType.__dict__.values():
            raise Exception("[SP_LoadSN]: snType must be sn1 or sn2")
        return self.SP_LoadSN(snType)

    @assertWait
    def sendUpdateSN(self,snType):
        """
        更新sn
        执行成功后，返回更新的SN
        :param snType:SN1/SN2
        :return:(True/False,result)
        """
        if snType is None or snType not in SnType.__dict__.values():
            raise Exception("[SP_LoadSN]: snType must be sn1 or sn2")
        return self.SP_UpdateSN(snType)

    @assertWait
    def sendATCommand(self, atCmd, wantReply, timeOut):
        """
        通过DIAG端口发送AT命令
        :param atCmd:at命令，类型string
        :param wantReply:是否需要at的返回值，类型bool
        :param timeOut:命令超时时间，单位毫秒，类型int
        :return:(True/False,result)
        """
        if not isinstance(atCmd, (str, unicode)):
            raise Exception("atCmd of SP_SendATCommand function must is string!")
        if not isinstance(wantReply, bool):
            raise Exception("bWantReply of SP_SendATCommand function must is bool!")
        if not isinstance(timeOut, int):
            raise Exception("timeOut of SP_SendATCommand function must is int!")

        return self.SP_SendATCommand(atCmd, wantReply, timeOut)

    @assertWait
    def sendSpecialAtCommand(self, atCmd, wantReply, timeOut):
        """
        通过DIAG端口发送以Ctrl+Z结束的特殊AT命令
        :param atCmd:at命令，类型string
        :param wantReply:是否需要执行at的返回值，类型bool
        :param timeOut:命令超时时间，单位毫秒，类型int
        :return:(True/False,result)
        """
        if not isinstance(atCmd, (str, unicode)):
            raise Exception("atCmd of sendSpecialAtCommand function must is string!")
        if not isinstance(wantReply, bool):
            raise Exception("wantReply of sendSpecialAtCommand function must is bool!")
        if not isinstance(timeOut, int):
            raise Exception("timeOut of sendSpecialAtCommand function must is int!")

        return self.SP_SendATCommand2(atCmd, wantReply, timeOut)

    @assertWait
    def sendAPGetBattery(self):
        """
        读取电池电量
        :return:(True/False,result)
        """
        return self.SP_apGetBatteryCapacity()

    @assertWait
    def sendGsmLoadCalFlag(self):
        """
        读取GSM/TD校准标志位
        :return:(True/False,result)
        """
        return self.SP_gsmLoadCalFlag()

    @assertWait
    def sendWcdmaLoad(self):
        """
        读取WCDMA校准标志位
        :return:(True/False,result)
        """
        return self.SP_wcdmaLoadCalFlag()

    @assertWait
    def sendLteLoadCalFlag(self):
        """
        读取LTE校准标志位
        :return:(True/False,result)
        """
        return self.SP_lteLoadCalFlag()

    def sendEnableArmLog(self, enable):
        """
        开启modem PS trace输出
        :return:(True/False,result)
        """
        return self.SP_EnableArmLog(enable)

    def sendAssertUE(self):
        """
        开启Assert Mode
        :return:(True/False,result)
        """
        return self.SP_AssertUE()

    @assertWait
    def sendPressKeyboard(self, keyCode):
        """
        发送按键命令
        :param keyCode:按键
        :return:(True/False,result)
        """
        if keyCode is None or keyCode not in KeyBoard.__dict__.values():
            raise Exception("keyCode of SP_PressKeyboard function must is int!")
        return self.SP_PressKeyboard(keyCode)

    @assertWait
    def sendPressKeyUpboard(self, keyCode):
        """
        发送按键放开动作命令
        :param keyCode:按键
        :return:True/False
        """
        if keyCode is None or keyCode not in KeyBoard.__dict__.values():
            raise Exception("keyCode of SP_PressKeyboard function must is int!")
        return self.SP_SendKeyUpCommand(keyCode)

    @assertWait
    def sendPressKeyDownboard(self, keyCode):
        """
        发送按键下压动作命令
        :param keyCode:按键
        :return: True/False
        """
        if keyCode is None or keyCode not in KeyBoard.__dict__.values():
            raise Exception("keyCode of SP_PressKeyboard function must is int!")
        return self.SP_SendKeyDownCommand(keyCode)

    @assertWait
    def sendTpUpCommand(self, x, y):
        """
        通过DIAG端口向TP层发送点击该坐标动作
        :param x: x坐标
        :param y: y坐标
        :return:
        """
        if not isinstance(x, int) or not isinstance(y, int):
            raise Exception("x or y  must be Int!")
        return self.SP_SendTPUpCommand(x, y)

    @assertWait
    def sendTpDownCommand(self, x, y):
        """
        通过DIAG端口向TP层发送放开该坐标动作
        :param x: x坐标
        :param y: y坐标
        :return:
        """
        if not isinstance(x, int) or not isinstance(y, int):
            raise Exception("x or y  must be Int!")
        return self.SP_SendTPDownCommand(x, y)

    @assertWait
    def sendTpMoveCommand(self, x, y):
        """
        通过DIAG端口向TP层发送移动到该坐标动作
        :param x: x坐标
        :param y: y坐标
        :return:
        """
        if not isinstance(x, int) or not isinstance(y, int):
            raise Exception("x or y  must be Int!")
        return self.SP_SendTPMoveCommand(x, y)

    @assertWait
    def sendDailCommand(self, phoneNumber):
        """
        拨打电话号码
        :param phoneNumber: 电话号码
        :return:(True/False,result)
        """
        if isinstance(phoneNumber, (str, unicode)):
            if not phoneNumber.isdigit():
                raise Exception("phoneNumber of sendDailCommand must be String!")
        else:
            raise Exception("phoneNumber of sendDailCommand must be String!")

        for pn in phoneNumber.replace(" ", ""):
            flag, result = self.sendPressKeyboard(ord(pn))
            time.sleep(0.2)
            if not flag:
                raise Exception(" Press key board({}) fail!".format(pn))
        flag, result =self.sendPressKeyboard(1)
        time.sleep(0.2)
        if not flag:
            raise Exception(" Press key board({}) fail!".format(1))
        return True, None

    @assertWait
    def sendVibrateOn(self, enable):
        """
        震动开关
        :param enable:True表示开启震动，False表示关闭震动
        :return:(True/False,result)
        """
        self.SP_VibrateOn(enable)

    @assertWait
    def sendReadNV(self, nvId):
        """
        读取指定ID的NV数据。
        :param nvId: Nv ID
        :return:(True/False, result(十六进制的字符串数组))
        """
        if not isinstance(nvId, (int, long)):
            raise Exception("nvId of sendReadNV must be int!")
        return self.SP_ReadNV(nvId)


    def openChannelSocketPort(self, port=36666, ip="127.0.0.1"):
        """
        开启数据层的socket对外提供的Port
        :param port: 新的端口
        :return:True/False
        """
        try:
            iniFilePath = os.path.join(os.path.split(os.path.abspath(__file__))[0],
                                       "diagDll\\PhoneCommand.ini")
            conObj = ConfigFileRead(iniFilePath)
            conObj.writeConfig("Socket", "Port", str(port))
            conObj.writeConfig("Socket", "Connect", str(1))
            conObj.writeConfig("Socket", "IP", str(ip))

            self.assertlinster.openChannel()
            return True
        except:
            return False


    def closeChannelSocketPort(self):
        """
        关闭数据层的socket对外提供的Port
        :param port: 新的端口
        :return:True/False
        """
        try:
            iniFilePath = os.path.join(os.path.split(os.path.abspath(__file__))[0],
                                       "diagDll\\PhoneCommand.ini")
            conObj = ConfigFileRead(iniFilePath)
            conObj.writeConfig("Socket", "Connect", str(0))
            return True
        except:
            return False

    def restartPhoneW317(self):
        """
        适用W317项目手机重启命令
        :return: False/True
        """
        return self.SP_Write('z')

    def sendAssertPrintCommand(self, command):
        """
        下发assert 打印命令
        :return: False/True
        """
        return self.SP_Write(command)

    def printAllAssertInfo(self):
        """
        下发t，z命令，打印assert information和重启手机
        :return:
        """
        self.sendAssertPrintCommand("t")

    def catchAssertByArmlogTools(self, armLogPath):
        """
        当assert时候，使用armlog工具抓取log
        :param armLogPath: armlog工具
        :return:
        """
        self._monitorAssert()
        self.assertlinster.openArmLogCatcherLog(armLogPath, self.port)

    def __check_phone_num(self, num):
        if not isinstance(num, str):
            num = str(num)
        ret = re.match(r"^1[35789]\d{9}$", num)
        if ret:
            return True
        else:
            return False

    def __handle_0_return(self, bol, ori_res):
        """
        处理ASBSIM工具新增功能中，只返回SUCC和FAIL的情况
        :param bol:
        :param ori_res:
        :return: SUC-True/FAIL-False
        """
        if not isinstance(bol, bool):
            raise Exception("handle 0 return error, params1 must be boolean")
        if not isinstance(ori_res, str):
            ori_res = str(ori_res)
        if ori_res.__contains__('SUC') & bol:
            return True
        else:
            return False

    def __handle_1_return(self, bol, ori_res):
        """
        处理ASBSIM工具新增功能中，返回一个params的情况
        :param bol:
        :param ori_res:
        :return: (False, get result failed/is empty)/(True, params)
        """
        if not isinstance(ori_res, str):
            ori_res = str(ori_res).upper()
        if ori_res.__eq__(""):
            return False, "get result is empty"
        if bol and ori_res.__contains__("SUC"):
            try:
                ori_splits = ori_res.split(",")
                if len(ori_splits) == 3:
                    return True, ori_splits[2]
            except Exception as e:
                pass
        if ori_res.__contains__("FAIL"):
            return False, "operation failed"
        return False, "unable to get result, ori_res is {}".format(ori_res)

    def __handle_2_return(self, bol, ori_res):
        """
            处理ASBSIM工具新增功能中，返回两个个params的情况
            :param bol:
            :param ori_res:
            :return: (False, get result failed/is empty)/(True, params)
        """
        if not isinstance(ori_res, str):
            ori_res = str(ori_res).upper()
        if ori_res.__eq__(""):
            return False, "get result is empty"
        if bol and ori_res.__contains__("SUC"):
            try:
                ori_splits = ori_res.split(",")
                if len(ori_splits) == 4:
                    res = list()

                    if ori_splits[2].__eq__(""):
                        res.append("empty value")
                    else:
                        res.append(ori_splits[2])

                    if ori_splits[3].__eq__(""):
                        res.append("empty value")
                    else:
                        res.append(ori_splits[3])
                    return True, res
            except Exception as e:
                pass
        return False, "failed to get result, ori_res is {}".format(ori_res)

    # ASBSIM工具新增功能
    @assertWait
    def get_battery_info(self):
        """
        获取电池信息
        :return:(False, None)/(True, 电池百分比, 充电电流)
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.GET_BATEERY.value)
        bol, res = self.SP_SendASBSIMNewCommand(hex_cmd)
        return self.__handle_2_return(bol, res)

    @assertWait
    def get_lcd_info(self):
        """
        获取lcd背光信息
        :return:(False, None)/(True, LCD背光刻度)
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.GET_LCD.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        return self.__handle_1_return(bol, ori_res)

    @assertWait
    def set_lcd(self, val):
        """
        设置lcd背光
        :param val: lcd刻度，1到7
        :return:Success/Failed
        """
        if not isinstance(val, int):
            raise Exception("val must be int")
        if val < 1 or val > 7:
            raise Exception("val out of boundary[1,7]")
        hex_cmd = diagCom.getASBSIMCommand(Common.SET_LCD.value + "," + str(val))
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "set lcd success"
        else:
            return "set lcd failed"

    @assertWait
    def go_to_IDEL(self):
        """
        回到待机界面
        :return:back to IDEL success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.IF_IDEL.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "back to IDEL success"
        else:
            return "back to IDEL failed"

    @assertWait
    def go_to_main_menu(self):
        """
        进入主界面
        :return:go to MainMenu success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.IF_MAIN_MENU.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "go to MainMenu success"
        else:
            return "go to MainMenu failed"

    @assertWait
    def get_lock_status(self):
        """
        获取锁屏状态
        :return:(True, KL_LOCKED...)/(False, None)
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.GET_LOCK_STATE.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        bol_res, result = self.__handle_1_return(bol, ori_res)
        if bol_res:
            try:
                for status in LockStatus:
                    if result.__eq__(status.value):
                        return bol_res, status.name
            except Exception:
                return False, "get lock status failed"
        return bol, result


    @assertWait
    def lock_screen(self):
        """
        立刻锁屏
        :return:lock screen success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.IF_LOCK_SCREEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "lock screen success"
        else:
            return "lock screen failed"

    @assertWait
    def unlock_screen(self):
        """
        解锁屏幕
        :return:unlock screen success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.IF_UNLOCK_SCREEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "unlock screen success"
        else:
            return "unlock screen failed"

    @assertWait
    def lock_screen_alarm(self, val):
        """
        设置x秒后锁屏
        :param val: x秒，
        :return:set lock screen success/failed
        """
        if not isinstance(val, int):
            raise Exception("parameter must be int")
        if (not val == 0) & (not val == 15) & (not val == 30) & (not val == 60) & (not val == 300):
            raise Exception("parameter must be 0/15/30/60/300")
        hex_cmd = diagCom.getASBSIMCommand(Common.SET_LOCK_TIME.value + "," + str(val))
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "set lock screen success"
        else:
            return "set lock screen failed"

    @assertWait
    def snap_shot(self):
        """
        屏幕截图
        :return:(False, None)/(True, SD卡路径和名称)
        """
        hex_cmd = diagCom.getASBSIMCommand(Common.SCREEN_SHOT.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        return self.__handle_1_return(bol, ori_res)

    @assertWait
    def is_call_open(self):
        """
        通话界面是否开启
        :return: Call Interface Open/Not Open
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.IS_CALL_OPEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "call interface opened"
        else:
            return "call interface not open or get message failed"

    @assertWait
    def open_call_interface(self):
        """
        开启通话界面
        :return:Open Call Interface Success/Failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.IF_CALL.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "open call interface success"
        else:
            return "open call interface failed"

    @assertWait
    def close_call_interface(self):
        """
        关闭通话界面
        :return:Close Call Interface Success/Failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.CLOSE_CALL.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "close call interface success"
        else:
            return "close call interface failed"

    @assertWait
    def get_call_status(self):
        """
        获取当前的通话状态
        :return:(False, None)/(True, CC_NULL_STATE...)
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.GET_CALL_STATUS.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        bol_res, result = self.__handle_1_return(bol, ori_res)
        if bol_res:
            try:
                for status in CallStatus:
                    if result.__eq__(status.value):
                        return bol_res, status.name
            except Exception:
                return False, "get call status failed"
        return bol, result

    @assertWait
    def call_out(self, sim, num):
        """
        拨打电话
        :return: call out success/failed
        """
        if sim not in SIM:
            raise Exception("sim must be SIM1/SIM2")
        if not isinstance(num, str):
            num = str(num)
        if not self.__check_phone_num(num):
            raise Exception("illegal phone number")
        hex_cmd = diagCom.getASBSIMCommand(Call.CALL_OUT.value + "," + sim.value + "," + num)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "call out success"
        else:
            return "call out failed"

    @assertWait
    def call_in(self):
        """
        接听当前电话
        :return:call in success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.CALL_IN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "call in success"
        else:
            return "call in failed"

    @assertWait
    def call_end(self):
        """
        挂断当前电话
        :return:call end success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Call.CALL_END.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "call end success"
        else:
            return "call end failed"

    @assertWait
    def is_msg_open(self):
        """
        是否已开启短信界面
        :return:MSG interface is open/not open
        """
        hex_cmd = diagCom.getASBSIMCommand(MSG.IS_MSG_OPEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "MSG interface is open"
        else:
            return "MSG interface not open or get message failed"

    @assertWait
    def open_msg(self):
        """
        开启短信界面
        :return:MSG interface open success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(MSG.IF_MSG.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "MSG interface open success"
        else:
            return "MSG interface open failed"

    @assertWait
    def close_msg(self):
        """
        关闭短信界面
        :return:MSG interface close success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(MSG.CLOSE_MSG.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "MSG interface close success"
        else:
            return "MSG interface close failed"

    @assertWait
    def send_msg(self, sim, num, content):
        """
        发送短信
        :param sim:
        :param num:
        :param content:
        :return:send message success/failed
        """
        if sim not in SIM:
            raise Exception("sim must be SIM1/SIM2")
        if not self.__check_phone_num(num):
            raise Exception("illegal phone number")
        if not isinstance(num, str):
            num = str(num)
        if not isinstance(content, str):
            raise Exception("content must be String")
        if len(content) > 612:
            raise Exception("content is too large, len(content) needs less than 612")
        hex_cmd = diagCom.getASBSIMCommand(MSG.MSG_SEND.value + "," + sim.value + "," + num + "," + content)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "send message success"
        else:
            return "send message failed"

    @assertWait
    def is_camera_open(self):
        """
        是否开启相机预览界面
        :return:camera interface is open/not open
        """
        hex_cmd = diagCom.getASBSIMCommand(Camera.IS_CAMERA_OPEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "camera interface is open"
        else:
            return "camera interface not open or get message failed"

    @assertWait
    def open_camera(self):
        """
        开启相机预览界面
        :return:open camera interface success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Camera.IF_CAMERA.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "open camera interface success"
        else:
            return "open camera interface failed"

    @assertWait
    def close_camera(self):
        """
        关闭相机界面
        :return:close camera interface success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Camera.CLOSE_CAMERA.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "close camera interface success"
        else:
            return "close camera interface failed"

    @assertWait
    def take_picture(self):
        """
        使用相机拍照
        :return:take picture success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Camera.TAKE_PICTURE.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "take picture success"
        else:
            return "take picture failed"

    @assertWait
    def is_audio_open(self):
        """
        是否已开启音乐播放器界面
        :return:audio player is open/not open
        """
        hex_cmd = diagCom.getASBSIMCommand(Audio.IS_AUDIO_OPEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "audio player is open"
        else:
            return "audio player not open or get message failed"

    @assertWait
    def get_audio_status(self):
        """
        获取音乐播放器当前的状态
        :return:(False, None)/(True, MMIMP3_AUDIO_OPENED...)
        """
        hex_cmd = diagCom.getASBSIMCommand(Audio.GET_AUDIO_STATUS.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        bol_res, result = self.__handle_1_return(bol, ori_res)
        if bol_res:
            try:
                for status in AudioStatus:
                    if result.__eq__(status.value):
                        return bol_res, status.name
            except Exception:
                return False, "get audio status failed"
        return bol, result

    @assertWait
    def open_audio(self):
        """
        开启音乐播放器界面
        :return:open audio player success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Audio.IF_AUDIO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "open audio player success"
        else:
            return "open audio player failed"

    @assertWait
    def close_audio(self):
        """
        关闭音乐播放器
        :return:close audio player success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Audio.CLOSE_AUDIO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "close audio player success"
        else:
            return "close audio player failed"

    @assertWait
    def play_current_audio(self):
        """
        播放当前音乐
        :return:play current audio success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Audio.PLAY_CURRENT_AUDIO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "play current audio success"
        else:
            return "play current audio failed"

    @assertWait
    def play_appoint_audio(self, path):
        """
        播放指定的音乐
        :param path:
        :return:play appointed audio success/failed
        """
        # todo 判断path是否为合法路径
        if not isinstance(path, str):
            raise Exception("audio path must be String")
        hex_cmd = diagCom.getASBSIMCommand(Audio.PLAY_APPOINTED_AUDIO.value + "," + path)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "play appointed audio success"
        else:
            return "play appointed audio failed"

    @assertWait
    def is_video_open(self):
        """
        是否已开启视频播放器界面
        :return:video interface is open/not open
        """
        hex_cmd = diagCom.getASBSIMCommand(Video.IS_VIDEO_OPEN.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "video interface is open"
        else:
            return "video interface not open or get message failed"

    @assertWait
    def get_video_status(self):
        """
        获取视频播放器当前的状态
        :return:(False, failed reason)/(True, VP_STATE_IDLE)
        """
        hex_cmd = diagCom.getASBSIMCommand(Video.VIDEO_STATUS.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        bol_res, result = self.__handle_1_return(bol, ori_res)
        if bol_res:
            try:
                for status in VideoStatus:
                    if result.__eq__(status.value):
                        return bol_res, status.name
            except Exception:
                return False, "get video status failed"
        return bol, result

    @assertWait
    def open_video(self):
        """
        开启视频播放器界面
        :return:open video success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Video.IF_VIDEO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "open video success"
        else:
            return "open video failed"

    @assertWait
    def close_video(self):
        """
        关闭视频播放器
        :return:close video success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Video.CLOSE_VIDEO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "close video success"
        else:
            return "close video failed"

    @assertWait
    def play_current_video(self):
        """
        播放当前视频
        :return:play current video success/failed
        """
        hex_cmd = diagCom.getASBSIMCommand(Video.PLAY_CURRENT_VIDEO.value)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "play current video success"
        else:
            return "play current video failed"

    @assertWait
    def play_appoint_video(self, path):
        """
        播放指定的视频
        :param path:
        :return:play appointed video success/failed
        """
        # todo 判断path是否为合法路径
        if not isinstance(path, str):
            raise Exception("path must be String")
        hex_cmd = diagCom.getASBSIMCommand(Video.PLAY_APPOINTED_VIDEO.value + "," + path)
        bol, ori_res = self.SP_SendASBSIMNewCommand(hex_cmd)
        if self.__handle_0_return(bol, ori_res):
            return "play appointed video success"
        else:
            return "play appointed video failed"


    @assertWait
    def send_custom_diag_command_7010(self, cmd):
        """
        发送自定义DiagCommand
        :param cmd:
        :return:
        """
        if not isinstance(cmd, str):
            raise Exception("cmd must be String")

        hex_cmd = diagCom.getASBSIMCommand(cmd, Type.TYPE_NONE_HEAD_IN_DATA_AREA)
        ori_res = self.SP_SendCustomDiagCommand(hex_cmd, "70", "10")
        if ori_res.__eq__(""):
            ori_res = "empty return"
        return ori_res